package org.arrowmania.scenes;

import org.arrowmania.engine.GameObject;
import org.arrowmania.engine.GameWorld;
import org.arrowmania.engine.GameWorld.CreateEvent;
import org.arrowmania.engine.GameWorld.DestroyEvent;
import org.arrowmania.engine.GameWorld.EventListener;
import org.arrowmania.engine.GameWorld.RenewalElem;
import org.arrowmania.engine.GameWorld.RenewalEvent;
import org.arrowmania.engine.beans.Point;
import org.arrowmania.engine.beans.RectArea;
import org.arrowmania.scenes.classes.GameConvertor;
import org.arrowmania.scenes.classes.GameInterface;
import org.cocos2d.actions.interval.CCMoveTo;
import org.cocos2d.actions.interval.CCRotateBy;
import org.cocos2d.actions.interval.CCSequence;
import org.cocos2d.layers.CCLayer;
import org.cocos2d.layers.CCScene;
import org.cocos2d.nodes.CCDirector;
import org.cocos2d.nodes.CCSprite;
import org.cocos2d.types.CGPoint;

import android.view.MotionEvent;

public class GameScene extends CCLayer{
	public static CCScene scene() {
		CCScene scene = CCScene.node();
		
		CCLayer layer = new GameScene();
		scene.addChild(layer);
		
		return scene;
	}

	public GameScene(){
		initScene();
		initConvertor();
		initWorld();
		
		world.addEventListener(new EventListener() {
			@Override
			public void renewal(RenewalEvent renewalEvent) {
				for(RenewalElem elem : renewalEvent.mRenewalsElems){
					CCSprite sprite = (CCSprite)world.getObject(elem.p1.x, elem.p1.y).getData();
					Point<Float> p = mConvertor.convertWorldPointToDisplayPoint(Point.make(elem.p2.x, elem.p2.y));
					CGPoint pos = CGPoint.make(p.x, p.y);
					
					sprite.runAction(CCMoveTo.action(1f, pos));
				}
			}
			
			@Override
			public void destroy(DestroyEvent destroyEvent) {
				for(Point<Integer> i:destroyEvent.mRemovingElems){
					world.setStateForObject(world.getObject(i.x,i.y),-1);
					CCSprite sprite = (CCSprite)(world.getObject(i.x, i.y).getData()); 
					removeChild(sprite, true);
				}
				
				mTotalScore += destroyEvent.mRemovingElems.size()*100*mFactor;
				mInterface.setScore(mTotalScore);
			}
			
			@Override
			public void create(CreateEvent createEvent) {
				for(Point<Integer> elem : createEvent.mCreateElems){
					int state = Math.round(3.0f*(float)Math.random());
					CCSprite sprite = CCSprite.sprite(arrows[state]);
					sprite.setScale(0.5f);
					
					sprite.setPosition(mConvertor.convertWorldPointToDisplayPoint(Point.make(elem.x, elem.y)).x, CCDirector.sharedDirector().displaySize().height + 50);
					
					Point<Float> p = mConvertor.convertWorldPointToDisplayPoint(Point.make(elem.x, elem.y));
					CGPoint pos = CGPoint.make(p.x, p.y);
					
					sprite.runAction(CCMoveTo.action(1f, pos));
					
					GameObject object = world.getObject(elem.x, elem.y);
					
					addChild(sprite);
					
					world.setDataForObject(object, sprite);
					world.setStateForObject(object, state);
				}
			}
		});
		
		schedule("idleRunLoop", 0.25f);
		
		addChild(mInterface);
	}

	protected void initScene() {
		this.setIsTouchEnabled(true);
		
		arrows[0] = "arrow_up.png";
		arrows[1] = "arrow_right.png";
		arrows[2] = "arrow_down.png";
		arrows[3] = "arrow_left.png";
	}
	
	protected void initWorld(){
		for(int i=0;i<world.getWidth();i++){
			for(int j=0;j<world.getHeight();j++){
				GameObject object = world.getObject(i, j);
				CCSprite sprite = CCSprite.sprite(arrows[object.getState()]);
				
				//XXX scale может быть разным для различных экранов
				//нужно сделать более общий scale для sprite'ов
				sprite.setScale(0.5f);
				
				Point<Float> p = mConvertor.convertWorldPointToDisplayPoint(Point.make(i, j));
				sprite.setPosition(p.x, p.y);
				
				world.setDataForObject(object, sprite);
				addChild(sprite);
			}
		}		
	}
	
	protected void initConvertor(){
		final float displayWidth = CCDirector.sharedDirector().displaySize().width;
		final float displayHeight = CCDirector.sharedDirector().displaySize().height;
		
		//XXX Убрать два числа и ввести переменные
		final RectArea worldArea = RectArea.make(6, 6);
		final Point<Float> startPoint = Point.make(CCDirector.sharedDirector().displaySize().width/2, CCDirector.sharedDirector().displaySize().height/2);
		
		mConvertor = GameConvertor.make(RectArea.make(displayWidth, displayHeight), worldArea, startPoint);
	}
		
	
	@Override
	public boolean ccTouchesEnded(MotionEvent event) {
		CGPoint p = CCDirector.sharedDirector().convertToGL(CGPoint.make(event.getX(), event.getY()));
		Point<Integer> q = mConvertor.convertDisplayPointToWorldPoint(Point.make(p.x, p.y));
		
		world.changeState((int)q.x, (int)q.y);
		rotateBlock((int)q.x, (int)q.y);
		
		schedule("idleRunLoop", 1f);
		
		return super.ccTouchesEnded(event);
	}

	//XXX не говорящее название. 
	public void idleRunLoop(float dt){
		unschedule("idleRunLoop");
		
		//Методы лучше поместить в один метод мира
		world.callDestroyEvent();
		world.callRenewalEvent();
		world.omitElems();
		world.callCreateEvent();
		
		if(world.isIdleRun() == true){
			mFactor++;
			schedule("idleRunLoop", 1f);
		} else {
			mFactor = 1;
		}
	}
	
	public void rotateBlock(int i, int j){
		this.setIsTouchEnabled(false);
		
		if((i < world.getWidth()-1) && (j < world.getHeight()-1)){
			if(world.getObject(i, j).getState() != -1){
				((CCSprite)(world.getObject(i, j).getData())).runAction(CCSequence.actions(CCRotateBy.action(1f, 90)));
			}
			
			if(world.getObject(i+1, j).getState() != -1){
				((CCSprite)(world.getObject(i+1, j).getData())).runAction(CCSequence.actions(CCRotateBy.action(1f, 90)));
			}
			
			if(world.getObject(i, j+1).getState() != -1){
				((CCSprite)(world.getObject(i, j+1).getData())).runAction(CCSequence.actions(CCRotateBy.action(1f, 90)));
			}
			
			if(world.getObject(i+1, j+1).getState() != -1){
				((CCSprite)(world.getObject(i+1, j+1).getData())).runAction(CCSequence.actions(CCRotateBy.action(1f, 90)));
			}
		}
		
		schedule("touchSwitcher", 1f);
	}
	
	public void touchSwitcher(float dt){
		this.setIsTouchEnabled(true);
		unschedule("touchSwitcher");
	}
	
	private String[] arrows = new String[4];
	//XXX Заменить числа на переменные
	private GameWorld world = new GameWorld(6, 6);
	
	private GameConvertor mConvertor;
	private GameInterface mInterface = new GameInterface();
	
	private int mTotalScore = 0;
	private int mFactor = 1;
}
